#include <iostream>
//
#include <task_run.hpp>

#if defined(CONFIG_TAR4ESP32)
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#else
#include <pthread.h>
#include <unistd.h>
#endif

void TaskRun::RtosTask(void* arg)
{
	if (arg == nullptr)
	{
		return;
	}

	TaskRun* task = (TaskRun*)arg;
	task->Run(task->m_TaskArg);
}

void* TaskRun::PthreadTaskRun(void* arg)
{
	if (arg == nullptr)
	{
		return nullptr;
	}

	TaskRun* task = (TaskRun*)arg;
	task->Run(task->m_TaskArg);
	task->m_Running = false;
	return nullptr;
}

void TaskRun::PthreadCreateTask(TaskRun* task)
{
	if (task == nullptr)
	{
		return;
	}

#if defined(CONFIG_TAR4ESP32)
	if (task->m_CpuId < 0 || task->m_CpuId >= E_CORE_CNT)
	{
		// xTaskCreate(&TaskRun::RtosTask,
		// 			task->m_TaskName.c_str(),
		// 			task->m_StackSize,
		// 			task,
		// 			task->m_Priority,
		// 			nullptr);
		task->m_CpuId = 0;
	}

	xTaskCreatePinnedToCore(&TaskRun::RtosTask,
							task->m_TaskName.c_str(),
							task->m_StackSize,
							task,
							task->m_Priority,
							nullptr,
							task->m_CpuId);
#else

	pthread_attr_t attr;
	if (pthread_attr_init(&attr) != 0)
	{
		LOG("pthread init attr error.\n");
		return;
	}

	struct sched_param param;
	param.sched_priority = task->m_Priority;
	if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0)
	{
		LOG("pthread set schedpolicy error.\n");
		return;
	}

	if (pthread_attr_setschedparam(&attr, &param) != 0)
	{
		LOG("pthread set schedparam error.\n");
		return;
	}

	pthread_t pth_id = 0;
	pthread_create(&pth_id, &attr, TaskRun::PthreadTaskRun, task);
	pthread_detach(pth_id);
#endif
}

void TaskRun::mSleep(uint32_t ms)
{
	if (ms == 0)
	{
		ms = 1;
	}

#if defined(CONFIG_TAR4ESP32)
	// CONFIG_FREERTOS_HZ=1000
	vTaskDelay(ms);
#else
	usleep(ms * 1000);
#endif
}

TaskRun::TaskRun(int priority, int stackSize, const char* taskName, int cpuId)
{
	this->m_Running	  = false;
	this->m_Priority  = priority;
	this->m_StackSize = stackSize;
	this->m_CpuId	  = m_CpuId;
	this->m_TaskName  = std::string(taskName);
}

TaskRun::~TaskRun()
{
}

void TaskRun::Start(void* arg)
{
	if (!this->m_Running)
	{
		this->m_Running = true;
		this->m_TaskArg = arg;
		TaskRun::PthreadCreateTask(this);
	}
}